package org.xx.armory.service;

import org.xx.armory.bindings.BoundParamCollection;
import org.xx.armory.rpc.Decorator;
import org.xx.armory.rpc.RpcRequest;
import org.xx.armory.rpc.RpcResponse;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static org.xx.armory.commons.Validators.notBlank;
import static org.xx.armory.commons.Validators.notNull;

/**
 * 模拟方法调用器。
 */
public final class MockInvocation
        implements Invocation {
    private final Object object;
    private final Method method;
    private final Decorator decorator;
    private boolean rawMethod;

    public MockInvocation(
            Object object,
            Method method,
            Decorator decorator
    ) {
        this.object = notNull(object, "object");
        this.method = notNull(method, "method");
        this.decorator = notNull(decorator, "decorator");
        this.rawMethod = false;
    }

    public MockInvocation(
            Class<?> serviceClass,
            String methodName,
            Decorator decorator
    )
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        notNull(serviceClass, "serviceClass");
        methodName = notBlank(methodName, "methodName").trim();

        final Constructor<?> constructor = serviceClass.getConstructor();
        constructor.setAccessible(true);
        this.object = constructor.newInstance();

        Method method = null;
        for (final Method method_ : serviceClass.getMethods()) {
            if (methodName.equals(method_.getName())) {
                method_.setAccessible(true);
                method = method_;
            }
        }
        this.method = notNull(method, "method");
        this.decorator = notNull(decorator, "decorator");
        this.rawMethod = false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RpcRequest getRequest() {
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RpcResponse getResponse() {
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Object getObject() {
        return this.object;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Method getMethod() {
        return this.method;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int[] getPermission() {
        return new int[0];
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Object execute(
            BoundParamCollection params,
            ServiceContext serviceContext
    )
            throws Throwable {
        if (this.rawMethod) {
            this.rawMethod = true;
            final Object result = this.decorator.execute(this, params, serviceContext);
            this.rawMethod = false;
            return result;
        } else {
            return this.method.invoke(this.object, params.values().toArray());
        }
    }
}
